home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / pascal / err87_13.zip / DECODE87.PAS next >
Pascal/Delphi Source File  |  1991-02-04  |  14KB  |  449 lines

  1. {$N+}
  2. unit decode87;
  3.  
  4.   { Unit to classify an 8087 instruction by its encoding }
  5. interface
  6. type
  7.   instruction =
  8.   (iF2XM1, iFABS, iFADD, iFADDP, iFBLD, iFBSTP, iFCHS, iFCLEX, iFCOM,
  9.    iFCOMP, iFCOMPP, iFCOS, iFDECSTP, iFDISI, iFDIV, iFDIVP, iFDIVR, iFDIVRP,
  10.    iFENI, iFFREE, iFIADD, iFICOM, iFICOMP, iFIDIV, iFIDIVR, iFILD, iFIMUL,
  11.    iFINCSTP, iFINIT, iFIST, iFISTP, iFISUB, iFISUBR, iFLD, iFLD1, iFLDCW,
  12.    iFLDENV, iFLDL2E, iFLDL2T, iFLDLG2, iFLDLN2, iFLDPI, iFLDZ, iFMUL, iFMULP,
  13.    iFNOP, iFPATAN, iFPREM, iFPREM1, iFPTAN, iFRNDINT, iFRSTOR, iFSAVE,
  14.    iFSCALE, iFSETPM, iFSIN, iFSINCOS, iFSQRT, iFST, iFSTCW, iFSTENV, iFSTP,
  15.    iFSTSW, iFSUB, iFSUBP, iFSUBR, iFSUBRP, iFTST, iFUCOM, iFUCOMP,
  16.    iFUCOMPP, iFXAM, iFXCH, iFXTRACT, iFYL2X, iFYL2XP1, iUnknown);
  17. const
  18.   inst_names : array[instruction] of String[7] =
  19.   ('F2XM1', 'FABS', 'FADD', 'FADDP', 'FBLD', 'FBSTP', 'FCHS', 'FCLEX', 'FCOM',
  20.    'FCOMP', 'FCOMPP', 'FCOS', 'FDECSTP', 'FDISI', 'FDIV', 'FDIVP', 'FDIVR', 'FDIVRP', 'FENI',
  21.    'FFREE', 'FIADD', 'FICOM', 'FICOMP', 'FIDIV', 'FIDIVR', 'FILD', 'FIMUL', 'FINCSTP',
  22.    'FINIT', 'FIST', 'FISTP', 'FISUB', 'FISUBR', 'FLD', 'FLD1', 'FLDCW', 'FLDENV', 'FLDL2E',
  23.    'FLDL2T', 'FLDLG2', 'FLDLN2', 'FLDPI', 'FLDZ', 'FMUL', 'FMULP', 'FNOP', 'FPATAN',
  24.    'FPREM', 'FPREM1', 'FPTAN', 'FRNDINT', 'FRSTOR', 'FSAVE', 'FSCALE', 'FSETPM', 'FSIN', 'FSINCOS', 'FSQRT', 'FST', 'FSTCW',
  25.    'FSTENV', 'FSTP', 'FSTSW', 'FSUB', 'FSUBP', 'FSUBR', 'FSUBRP', 'FTST', 'FUCOM',
  26.    'FUCOMP', 'FUCOMPP', 'FXAM', 'FXCH', 'FXTRACT', 'FYL2X', 'FYL2XP1', '');
  27. type
  28.   reg_count = 0..8;
  29.  
  30.   operand_type = (arReg0, arReg1, arReg2, arReg3, arReg4, arReg5, arReg6,
  31.                   arReg7, arWord, arLongint, arComp, arBCD,
  32.                   arSingle, arDouble, arExtended, arControl, arStatus,
  33.                   arEnviron, arState, arNone);
  34.   operand_set = set of operand_type;
  35. const
  36.   arg_names : array[operand_type] of String[8] =
  37.   ('Reg0', 'Reg1', 'Reg2', 'Reg3', 'Reg4', 'Reg5', 'Reg6',
  38.    'Reg7', 'Word', 'Longint', 'Comp', 'BCD',
  39.    'Single', 'Double', 'Extended', 'Control', 'Status',
  40.    'Environ', 'State', 'None');
  41.  
  42. type
  43.   opcode_info = record
  44.                   inst     : instruction;
  45.                   arg1, arg2 : operand_type;
  46.                 end;
  47.  
  48. procedure decode_opcode(opcode : Word; var result : opcode_info);
  49.  
  50. procedure operands_read(inst_info : opcode_info; var ops_read : operand_set);
  51.  
  52. function num_pops(inst_info : opcode_info) : reg_count;
  53.  
  54. function num_pushes(inst_info : opcode_info) : reg_count;
  55.  
  56. function limited(inst_info : opcode_info): boolean;
  57.  
  58. function lower_limit(inst_info : opcode_info) : extended;
  59.   { least legal operand }
  60.  
  61. function upper_limit(inst_info : opcode_info) : extended;
  62.   { greatest legal operand }
  63.  
  64.  
  65. implementation
  66. const
  67.   Plus_Infinity_Array : array[1..2] of word = (0, $7f80);
  68. var
  69.   Plus_Infinity : single absolute Plus_Infinity_Array;
  70. const
  71.   Minus_Infinity_Array : array[1..2] of word = (0, $ff80);
  72. var
  73.   Minus_Infinity : single absolute Minus_Infinity_Array;
  74.  
  75.   procedure operands_read(inst_info : opcode_info; var ops_read : operand_set);
  76.   const
  77.     reads_reg0 =
  78.     [iF2XM1, iFABS, iFADD, iFADDP, iFBSTP, iFCHS, iFCOM,
  79.     iFCOMP, iFCOMPP, iFCOS, iFDIV, iFDIVP, iFDIVR, iFDIVRP,
  80.     iFIADD, iFICOM, iFICOMP, iFIDIV, iFIDIVR, iFIMUL,
  81.     iFIST, iFISTP, iFISUB, iFISUBR, iFMUL, iFMULP,
  82.     iFPATAN, iFPREM, iFPREM1, iFPTAN, iFRNDINT,
  83.     iFSCALE, iFSIN, iFSINCOS, iFSQRT, iFST, iFSTP,
  84.     iFSUB, iFSUBP, iFSUBR, iFSUBRP, iFTST, iFUCOM, iFUCOMP,
  85.     iFUCOMPP, iFXAM, iFXCH, iFXTRACT, iFYL2X, iFYL2XP1];
  86.     reads_reg1 =
  87.     [iFPATAN, iFPREM, iFSCALE, iFYL2X, iFYL2XP1];
  88.     reads_arg1 =
  89.     [iFADD, iFADDP, iFBLD, iFCOM, iFCOMP, iFCOMPP, iFDIV, iFDIVP,
  90.     iFDIVR, iFDIVRP, iFIADD, iFICOM, iFICOMP, iFIDIV, iFIDIVR, iFILD, iFIMUL,
  91.     iFISUB, iFISUBR, iFLD, iFLDCW, iFLDENV, iFMUL, iFMULP,
  92.     iFRSTOR, iFSUB, iFSUBP, iFSUBR, iFSUBRP, iFTST, iFUCOM, iFUCOMP,
  93.     iFUCOMPP, iFXAM, iFXCH];
  94.  
  95.   begin
  96.     with inst_info do
  97.     begin
  98.       if inst in reads_reg0 then
  99.         ops_read := [arReg0]
  100.       else
  101.         ops_read := [];
  102.       if inst in reads_reg1 then
  103.         ops_read := ops_read+[arReg1];
  104.       if (arg1 <> arNone) and (inst in reads_arg1) then
  105.         ops_read := ops_read+[arg1];
  106.       if arg2 <> arNone then
  107.         ops_read := ops_read+[arg2];
  108.     end;
  109.   end;
  110.  
  111.   function num_pops(inst_info : opcode_info) : reg_count;
  112.   const
  113.     two_pop  = [iFCOMPP, iFUCOMPP];
  114.     pops =
  115.     [iFADDP, iFBSTP, iFCOMP, iFDIVP, iFDIVRP, iFICOMP, iFISTP, iFMULP,
  116.     iFPATAN, iFSTP, iFSUBP, iFSUBRP, iFUCOMP, iFYL2X, iFYL2XP1]+two_pop;
  117.   begin
  118.     if inst_info.inst in pops then
  119.       if inst_info.inst in two_pop then
  120.         num_pops := 2
  121.       else
  122.         num_pops := 1
  123.     else
  124.       num_pops := 0;
  125.   end;
  126.  
  127.   function num_pushes(inst_info : opcode_info) : reg_count;
  128.   const
  129.     does_push =
  130.     [iFBLD, iFILD, iFLD, iFLD1, iFLDL2E, iFLDL2T, iFLDLG2, iFLDLN2,
  131.     iFLDPI, iFLDZ, iFPTAN, iFSINCOS, iFXTRACT];
  132.   begin
  133.     if inst_info.inst in does_push then
  134.       num_pushes := 1
  135.     else
  136.       num_pushes := 0;
  137.   end;
  138.  
  139. function limited(inst_info:opcode_info):boolean;
  140. const
  141.   limited_instructions =
  142.   [iF2XM1 {0 to 0.5} , iFPATAN {0 < Y < X < pinf} ,
  143.   iFPTAN {0 to pi/4} , iFSCALE {won't cause exception, but -2^15<Y<2^15} ,
  144.   iFSQRT {0 to pinf} , iFYL2X {0 < X < pinf} ,
  145.   iFYL2XP1 {|X| < (1-1/sqrt(2))} ];
  146. begin
  147.   limited := inst_info.inst in limited_instructions;
  148. end;
  149.  
  150.  
  151.   function lower_limit(inst_info : opcode_info) : extended;
  152.   begin
  153.     if limited(inst_info) then
  154.       case inst_info.inst of
  155.         iF2XM1,
  156.         iFPATAN,
  157.         iFPTAN,
  158.         iFSQRT,
  159.         iFYL2X : lower_limit := 0.0;
  160.         iFSCALE : lower_limit := -32768;
  161.         iFYL2XP1 : lower_limit := -(1-1/Sqrt(2));
  162.       end
  163.     else
  164.       lower_limit := minus_infinity;
  165.   end;
  166.  
  167.   function upper_limit(inst_info : opcode_info) : extended;
  168.   begin
  169.     if limited(inst_info)  then
  170.       case inst_info.inst of
  171.         iF2XM1 : upper_limit := 0.5;
  172.         iFSQRT,
  173.         iFYL2X,
  174.         iFPATAN : upper_limit := plus_infinity;
  175.         iFPTAN : upper_limit := pi/4;
  176.         iFSCALE : upper_limit := 32768;
  177.         iFYL2XP1 : upper_limit := (1-1/Sqrt(2));
  178.       end
  179.     else
  180.       upper_limit := plus_infinity;
  181.   end;
  182.   procedure decode_opcode(opcode : Word; var result : opcode_info);
  183.  
  184.   { This routine and those within it are closely based on UNINLINE,
  185.     by L. David Baldwin. }
  186.  
  187.   var
  188.     opbyte1,
  189.     opbyte2,
  190.     rm,
  191.     mode,
  192.     middle   : Byte;
  193.     memory_reference : Boolean;
  194.  
  195.     procedure ReadModeByte;
  196.     {read the mode byte and sort out the various parts.  read the
  197.      displacement byte or word if req'D}
  198.     var Modebyte : Byte;
  199.     begin
  200.       Modebyte := opbyte2;
  201.       rm := Modebyte and 7;
  202.       mode := (Modebyte and $C0) div 64;
  203.       middle := (Modebyte and $38) div 8;
  204.       if (mode = 0) and (rm = 6) or (mode = 2) or (mode = 1) then
  205.         memory_reference := True;
  206.     end;
  207.  
  208.     procedure ST_i;               {do st(i) }
  209.     begin
  210.       result.arg1 := operand_type(Word(rm));
  211.     end;
  212.  
  213.     procedure STi_ST;             {do st(i),st }
  214.     begin
  215.       ST_i;
  216.       result.arg2 := arReg0;
  217.     end;
  218.  
  219.     procedure ST_STi;             { do st,st(i) }
  220.     begin
  221.       ST_i;
  222.       with result do
  223.       begin
  224.         arg2 := arg1;
  225.         arg1 := arReg0;
  226.       end;
  227.     end;
  228.  
  229.     procedure DB;
  230.     const inst_list : array[0..12] of instruction =
  231.       (iFILD, iUnknown, iFIST, iFISTP, iUnknown, iFLD, iUnknown,
  232.        iFSTP, iFENI, iFDISI, iFCLEX, iFINIT, iFSETPM);
  233.     var I    : Word;
  234.       Tmp      : instruction;
  235.     begin
  236.       ReadModeByte;
  237.       if (mode = 3) then
  238.         I := rm+8
  239.       else
  240.         I := middle;              {form an index}
  241.       Tmp := inst_list[I];
  242.       if (Tmp <> iUnknown) and (I <= 12) then
  243.       begin
  244.         result.inst := Tmp;
  245.         if I <= 3 then
  246.           result.arg1 := arLongint
  247.         else
  248.           if I <= 7 then
  249.             result.arg1 := arExtended
  250.       end
  251.